// 071205;080404 alexch
//
// ==========  This file is under  LGPL, the GNU Lesser General Public Licence
// ==========  Dialing Lemmatizer (www.aot.ru)
// ==========  Copyright by Alexey Sokirko 
//
// ==========  Visual Studio project for 32/64 bit DLL-wrapper
// ==========  Created by Hulbee AG

#ifndef __GUARDS_H
#define __GUARDS_H

#include <windows.h>
#include <malloc.h>
#include <wchar.h>

#ifdef GUARDS_DLLEXPORT
	#define DECL_MOD __declspec(dllexport)
#else
	#define DECL_MOD
#endif

class DECL_MOD SmartBuffer
{
public:
	BYTE *mem;
	SmartBuffer(): mem(0)
	{
	}
	SmartBuffer(DWORD bufSize)
	{
		mem = new BYTE[bufSize];
	}
	~SmartBuffer()
	{
		delete[] mem;
	}
	void AllocNew(DWORD bufSize)
	{
		void *temp = mem;
		mem = 0;
		delete[] temp;
		mem = new BYTE[bufSize];
	}
	void* GetMem()
	{
		void* ret = mem;
		mem = 0;
		return ret;
	}
};

typedef void OnFree(void *param);

class DECL_MOD Guard
{
protected:
	OnFree *m_onFree;
	void *m_param;
public:
	Guard(): m_onFree(0)
	{
	}
	Guard(OnFree *onFree, void *param): m_onFree(onFree), m_param(param)
	{
	}
	~Guard()
	{
		if (m_onFree)
			m_onFree(m_param);
	}
	void SetOnFree(OnFree *onFree, void *param)
	{
		m_onFree = onFree;
		m_param = param;
	}
};

class DECL_MOD MemoryGuard
{
protected:
	void *mem;
public:
	MemoryGuard(): mem(0)
	{
	}
	~MemoryGuard()
	{
		free(mem);
	}
	void SetMem(void *_mem)
	{
		mem = _mem;
	}
};

class DECL_MOD HandleGuard
{
	HANDLE h;
public:
	HandleGuard(): h(INVALID_HANDLE_VALUE) {}
	HandleGuard(HANDLE handle): h(handle) {}
	~HandleGuard()
	{
		if (h != INVALID_HANDLE_VALUE)
			CloseHandle(h);
	}
	bool SetHandle(HANDLE handle)
	{
		Close();
		h = handle;
		return handle != INVALID_HANDLE_VALUE;
	}
	bool Close();
	bool IsSet()
	{
		return h != INVALID_HANDLE_VALUE;
	}
	HANDLE Handle()
	{
		return h;
	}
	HANDLE operator()()
	{
		return h;
	}
};

class DECL_MOD Handle0Guard
{
	HANDLE h;
public:
	Handle0Guard(): h(0) {}
	Handle0Guard(HANDLE handle): h(handle) {}
	~Handle0Guard() {
		if (h != 0)
			CloseHandle(h);
	}
	bool SetHandle(HANDLE handle)
	{
		Close();
		h = handle;
		return handle != 0;
	}
	bool Close();
	bool IsSet()
	{
		return h != 0;
	}
	HANDLE Handle()
	{
		return h;
	}
	HANDLE operator()()
	{
		return h;
	}
};

class DECL_MOD LibraryGuard
{
	HMODULE h;
public:
	LibraryGuard(): h(0) {}
	LibraryGuard(HMODULE handle): h(handle) {}
	~LibraryGuard()
	{
		if (h != 0)
			FreeLibrary(h);
	}
	bool SetHandle(HMODULE handle)
	{
		Close();
		h = handle;
		return handle != 0;
	}
	bool Close();
	HMODULE Load(LPCSTR name, bool disableErrors);
	HMODULE Load(LPCWSTR name, bool disableErrors);
	HMODULE Handle()
	{
		return h;
	}
	HMODULE operator()()
	{
		return h;
	}
};

class DECL_MOD RegKeyGuard
{
	HKEY h;
	bool initialized;
public:
	RegKeyGuard(): initialized(false) {}
	RegKeyGuard(HKEY key): h(key), initialized(true) {}
	~RegKeyGuard()
	{
		if (initialized)
			RegCloseKey(h);
	}
	void SetKey(HKEY key)
	{
		Close();
		h = key;
		initialized = true;
	}
	HKEY Key()
	{
		return initialized ? h : 0;
	}
	bool Close()
	{
		if (initialized) {
			LONG ret = RegCloseKey(h);
			initialized = false;
			return ret == ERROR_SUCCESS;
		}
		else
			return false;
	}
	bool Open(HKEY rootKey, LPCSTR subKey, REGSAM samDesired, HKEY *key = 0, LONG *code = 0);
	bool OpenRead(HKEY rootKey, LPCSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Open(rootKey, subKey, KEY_READ, key, code);
	}
	bool OpenForAll(HKEY rootKey, LPCSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Open(rootKey, subKey, KEY_ALL_ACCESS, key, code);
	}
	bool Open(HKEY rootKey, LPCWSTR subKey, REGSAM samDesired, HKEY *key = 0, LONG *code = 0);
	bool OpenRead(HKEY rootKey, LPCWSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Open(rootKey, subKey, KEY_READ, key, code);
	}
	bool OpenForAll(HKEY rootKey, LPCWSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Open(rootKey, subKey, KEY_ALL_ACCESS, key, code);
	}
	bool Create(HKEY rootKey, LPCSTR subKey, REGSAM samDesired, HKEY *key = 0, LONG *code = 0);
	bool CreateRead(HKEY rootKey, LPCSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Create(rootKey, subKey, KEY_READ, key, code);
	}
	bool CreateForAll(HKEY rootKey, LPCSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Create(rootKey, subKey, KEY_ALL_ACCESS, key, code);
	}
	bool Create(HKEY rootKey, LPCWSTR subKey, REGSAM samDesired, HKEY *key = 0, LONG *code = 0);
	bool CreateRead(HKEY rootKey, LPCWSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Create(rootKey, subKey, KEY_READ, key, code);
	}
	bool CreateForAll(HKEY rootKey, LPCWSTR subKey, HKEY *key = 0, LONG *code = 0)
	{
		return Create(rootKey, subKey, KEY_ALL_ACCESS, key, code);
	}
	bool GetStringValue(LPCSTR valueName, CHAR* buf, DWORD bufSize);
	bool GetStringValue(LPCWSTR valueName, WCHAR *buf, DWORD bufSize);
};

class DECL_MOD FindGuard
{
	HANDLE h;
public:
	FindGuard(): h(INVALID_HANDLE_VALUE) {}
	FindGuard(HANDLE handle): h(handle) {}
	~FindGuard()
	{
		if (h != INVALID_HANDLE_VALUE)
			FindClose(h);
	}
	bool SetHandle(HANDLE handle)
	{
		Close();
		h = handle;
		return handle != INVALID_HANDLE_VALUE;
	}
	bool Close()
	{
		if (h != INVALID_HANDLE_VALUE) {
			BOOL ret = FindClose(h);
			h = INVALID_HANDLE_VALUE;
			return ret != FALSE;
		}
		else
			return false;
	}
};

class DECL_MOD CriticalSectionGuard {
protected:
	PRTL_CRITICAL_SECTION m_pcs;
	DWORD m_entered;
public:
	CriticalSectionGuard(PRTL_CRITICAL_SECTION pcs): m_pcs(pcs), m_entered(0) {}
	virtual ~CriticalSectionGuard()
	{
		while (m_entered--)
			LeaveCriticalSection(m_pcs);
	}
	void Enter()
	{
		EnterCriticalSection(m_pcs);
		++m_entered;
	}
#if(_WIN32_WINNT >= 0x0400)
	bool TryEnter(DWORD time, DWORD sleepTime);
#endif
	void Leave()
	{
		if (m_entered) {
			LeaveCriticalSection(m_pcs);
			--m_entered;
		}
	}
};

class DECL_MOD CriticalSection {
protected:
	RTL_CRITICAL_SECTION m_cs;
public:
	CriticalSection()
	{
		InitializeCriticalSection(&m_cs);
	}
	~CriticalSection()
	{
		DeleteCriticalSection(&m_cs);
	}
	void Enter()
	{
		EnterCriticalSection(&m_cs);
	}
#if(_WIN32_WINNT >= 0x0400)
	bool TryEnter(DWORD time, DWORD sleepTime);
#endif
	void Leave()
	{
		LeaveCriticalSection(&m_cs);
	}
	RTL_CRITICAL_SECTION *operator()()
	{
		return &m_cs;
	}
};

class DECL_MOD CriticalSectionGuard2 {
protected:
	CriticalSection *m_cs;
	DWORD m_entered;
public:
	CriticalSectionGuard2(CriticalSection *cs): m_cs(cs), m_entered(0) {}
	~CriticalSectionGuard2()
	{
		if (m_cs)
			while (m_entered--)
				m_cs->Leave();
	}
	void Enter()
	{
		if (m_cs) {
			m_cs->Enter();
			++m_entered;
		}
	}
#if(_WIN32_WINNT >= 0x0400)
	bool TryEnter(DWORD time, DWORD sleepTime)
	{
		if (!m_cs)
			return false;
		bool ret = m_cs->TryEnter(time, sleepTime);
		m_entered += (DWORD)ret;
		return ret;
	}
#endif
	void Leave()
	{
		if (m_cs && m_entered) {
			m_cs->Leave();
			--m_entered;
		}
	}
};

template<class T> class ObjectGuard {
private:
	T *m_t;
public:
	ObjectGuard(): m_t(0) {}
	ObjectGuard(T *t) { m_t = t; }
	~ObjectGuard()
	{
		delete m_t;
	}
	void Set(T *t)
	{
		m_t = t;
	}
};

#endif
